package com.lucenex.service;



import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;

import com.ld.ThreadPool.LdThreadPool;
import com.ld.ThreadPool.LoggerFactory;
import com.ld.ThreadPool.core.LdFuture;
import com.ld.ThreadPool.core.LdFutureListener;
import com.ld.ThreadPool.core.LdThreadPoolFactory;
import com.lucenex.base.BaseLuceneXDao;
import com.lucenex.core.LuceneDataSource;
import com.lucenex.util.ObjectKit;
import com.lucenex.util.Page;

public class LuceneServiceImpl implements LuceneService {

	private BaseLuceneXDao indexDao;

	private Logger logger = LoggerFactory.getLogger(LuceneServiceImpl.class);

	/**
	 * 线程池处理
	 */
	private LdThreadPoolFactory ldThreadPool = LdThreadPool.build().get();

	public LuceneServiceImpl(String sourceKey){
		LuceneDataSource.setDatabaseType(sourceKey);
		indexDao = new BaseLuceneXDao();
	}


	@Override
	public <T> void saveObj(List<T> objects){
		asynchronous(()->{
			saveDocument(ObjectKit.objToDocs(objects));
		});
	}


	@Override
	public <T> void saveObj(T object){
		asynchronous(()->{
			saveDocument(ObjectKit.objToDoc(object));
		});

	}

	@Override
	public <T> void saveMap(List<T> maps, Class<?> clas){
		asynchronous(()->{
			saveDocument(ObjectKit.mapToDocs(maps, clas));
		});
	}


	@Override
	public <T> void saveMap(T map, Class<?> clas) {
		asynchronous(()->{
			saveDocument(ObjectKit.mapToDoc(map, clas));
		});
	}


	@Override
	public <T> void saveDocument(List<Document> documents) {
		asynchronous(()->{
			try {
				indexDao.saveIndex(documents);
			} catch (IOException e) {
				logger.log(Level.SEVERE, "luceneService saveMap saveDoc error", e);
			}
		});
	}


	@Override
	public <T> void saveDocument(Document document) {
		asynchronous(()->{
			try {
				indexDao.saveIndex(document);
			} catch (IOException e) {
				logger.log(Level.SEVERE, "luceneService saveMap saveDoc error", e);
			}
		});
	}


	@Override
	public <T> void updateObj(List<T> objs, Term term) {
		asynchronous(()->{
			updateDocument(ObjectKit.objToDocs(objs), term);
		});
	}


	@Override
	public <T> void updateObj(T obj, Term term) {
		asynchronous(()->{
			updateDocument(ObjectKit.objToDoc(obj), term);
		});
	}

	@Override
	public <T> void updateObj(List<T> object, Query query) {
		asynchronous(()->{
			try {
				updateDocument(ObjectKit.objToDocs(object), query);
			} catch (Exception e) {
				logger.log(Level.SEVERE, "luceneService updateObj updateDoc error", e);
			}
		});

	}


	@Override
	public <T> void updateObj(T object, Query query){
		asynchronous(()->{
			try {
				updateDocument(ObjectKit.objToDoc(object), query);
			} catch (Exception e) {
				logger.log(Level.SEVERE, "luceneService updateObj updateDoc error", e);
			}
		});
	}


	@Override
	public <T> void updateMap(List<T> map, Term term, Class<?> clas){
		asynchronous(()->{
			updateDocument(ObjectKit.mapToDocs(map, clas), term);
		});
	}


	@Override
	public <T> void updateMap(T map, Term term, Class<?> clas) {
		asynchronous(()->{
			updateDocument(ObjectKit.mapToDoc(map, clas), term);
		});
	}

	@Override
	public <T> void updateMap(List<T> map, Query query, Class<?> clas) {
		asynchronous(()->{
			try {
				updateDocument(ObjectKit.mapToDocs(map, clas), query);
			} catch (Exception e) {
				logger.log(Level.SEVERE, "luceneService updateMap updateDocument error", e);
			}
		});

	}


	@Override
	public <T> void updateMap(T map, Query query, Class<?> clas){
		asynchronous(()->{
			try {
				updateDocument(ObjectKit.mapToDoc(map, clas), query);
			} catch (Exception e) {
				logger.log(Level.SEVERE, "luceneService updateMap updateDocument error", e);
			}
		});
	}



	@Override
	public void updateDocument(List<Document> docs, Term term) {
		asynchronous(()->{
			try {
				indexDao.updateIndex(docs, term);
			} catch (Exception e) {
				logger.log(Level.SEVERE, "luceneService updateDocument updateIndex error", e);
			}
		});
	}


	@Override
	public void updateDocument(Document doc, Term term) {
		asynchronous(()->{
			try {
				indexDao.updateIndex(doc, term);
			} catch (Exception e) {
				logger.log(Level.SEVERE, "luceneService updateDocument updateIndex error", e);
			}
		});

	}
	@Override
	public void updateDocument(List<Document> document, Query query) {
		asynchronous(()->{
			try {
				indexDao.updateIndex(document, query);
			} catch (Exception e) {
				logger.log(Level.SEVERE, "luceneService updateDocument updateIndex error", e);
			}
		});
	}


	@Override
	public void updateDocument(Document document, Query query) {
		asynchronous(()->{
			try {
				indexDao.updateIndex(document, query);
			} catch (Exception e) {
				logger.log(Level.SEVERE, "luceneService updateDocument updateIndex error", e);
			}
		});
	}


	@Override
	public <T> List<T> findList(Query query, Class<T> obj, int num, Sort sort) throws IOException, InvalidTokenOffsetsException, InstantiationException, IllegalAccessException, NoSuchFieldException, InvocationTargetException {
		return indexDao.findList(query, obj, num, sort);
	}


	@Override
	public <T> Page<T> findList(Query query, int pageNumber, int pageSize, Class<T> obj, Sort sort) throws IOException, InvalidTokenOffsetsException, InstantiationException, IllegalAccessException, NoSuchFieldException, InvocationTargetException {
		return indexDao.findList(query, pageNumber, pageSize, obj, sort);
	}


	@Override
	public void delAll() throws IOException {
		indexDao.delAll();
	}


	@Override
	public void delKey(Term term) throws IOException {
		indexDao.deletekey(term);
	}


	@Override
	public void delKey(Query query) throws IOException {
		indexDao.deletekey(query);
	}
	
	/**
	 * 异步执行  回调同步
	 * @param runnable
	 */
	private void asynchronous(Runnable runnable) {
		LdFuture<Boolean> ldFuture = ldThreadPool.submit(new Callable<Boolean>() {
			@Override
			public Boolean call() throws Exception {
				runnable.run();
				return null;
			}
		});
		ldFuture.addListener(new LdFutureListener<Boolean>() {
			@Override
			public void success(Boolean v) {
				indexDao.realTime();
				logger.info("save/update end & synchronization end");
			}
			
			@Override
			public void error(Throwable throwable) {
				throwable.printStackTrace();
				logger.info("ERROR save/update");
			}
		});
	}
}
